package com.xinshujia.config;

import com.xinshujia.config.authentication.provider.MyPhoneAuthenticationProvider;
import com.xinshujia.config.authentication.provider.MyUsernamePasswordAuthenticationProvider;
import com.xinshujia.config.authentication.service.MyPhoneDetailsService;
import com.xinshujia.config.authentication.service.MyUsernamePasswordDetailsService;
import com.xinshujia.config.authorization.MyAuthorizationManager;
import com.xinshujia.filter.authentication.JwtAuthenticationTokenFilter;
import com.xinshujia.filter.authentication.MyPhoneAuthenticationFilter;
import com.xinshujia.filter.authentication.MyUsernamePasswordAuthenticationFilter;
import com.xinshujia.handler.MyAuthenticationFailureHandler;
import com.xinshujia.handler.MyAuthenticationSuccessHandler;
import com.xinshujia.handler.MyLogoutSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Arrays;

/**
 * @author: 野狼上校
 * @create: 2023-03-16  10:02
 * @version: 1.0
 * @description:
 */
@Configuration
public class MySecurityConfig {
    private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    private final MyAuthorizationManager myAuthorizationManager;
    private final MyUsernamePasswordAuthenticationProvider myUsernamePasswordAuthenticationProvider;
    private final MyPhoneAuthenticationProvider myPhoneAuthenticationProvider;
    private final MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    private final MyUsernamePasswordDetailsService myUsernamePasswordDetailsService;

    public MySecurityConfig(JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter, MyAuthorizationManager myAuthorizationManager, MyUsernamePasswordAuthenticationProvider myUsernamePasswordAuthenticationProvider, MyPhoneAuthenticationProvider myPhoneAuthenticationProvider, MyAuthenticationSuccessHandler myAuthenticationSuccessHandler, MyUsernamePasswordDetailsService myUsernamePasswordDetailsService) {
        this.jwtAuthenticationTokenFilter = jwtAuthenticationTokenFilter;
        this.myAuthorizationManager = myAuthorizationManager;
        this.myUsernamePasswordAuthenticationProvider = myUsernamePasswordAuthenticationProvider;
        this.myPhoneAuthenticationProvider = myPhoneAuthenticationProvider;
        this.myAuthenticationSuccessHandler = myAuthenticationSuccessHandler;
        this.myUsernamePasswordDetailsService = myUsernamePasswordDetailsService;
    }

    /* 登录认证管理器配置 */
    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Arrays.asList(myUsernamePasswordAuthenticationProvider, myPhoneAuthenticationProvider));
    }

    /**
     * 账号登录
     */
    @Bean
    public MyUsernamePasswordAuthenticationFilter usernameLoginFilter(AuthenticationManager authenticationManager) {
        MyUsernamePasswordAuthenticationFilter usernameLoginFilter = new MyUsernamePasswordAuthenticationFilter();
        usernameLoginFilter.setUsernameParameter("username");
        usernameLoginFilter.setPasswordParameter("password");
        usernameLoginFilter.setFilterProcessesUrl("/login/login1");
        usernameLoginFilter.setAuthenticationManager(authenticationManager);
        /*认证成功处理器*/
        usernameLoginFilter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
        /*认证失败处理器*/
        usernameLoginFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
        return usernameLoginFilter;
    }

    /**
     * 手机号码登录
     */
    @Bean
    public MyPhoneAuthenticationFilter phoneLoginFilter(AuthenticationManager authenticationManager){
        MyPhoneAuthenticationFilter phoneLoginFilter = new MyPhoneAuthenticationFilter();
        phoneLoginFilter.setPasswordParameter("phone");
        phoneLoginFilter.setPasswordParameter("password");
        phoneLoginFilter.setFilterProcessesUrl("/login/login2");
        phoneLoginFilter.setAuthenticationManager(authenticationManager);
        /*认证成功处理器*/
        phoneLoginFilter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
        /*认证失败处理器*/
        phoneLoginFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
        return phoneLoginFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, MyPhoneDetailsService myPhoneDetailsService) throws Exception {
        httpSecurity
                // csrf配置
                .csrf(AbstractHttpConfigurer::disable)
                // cors配置
                .cors(AbstractHttpConfigurer::disable)
                //禁用Session 的机制
                .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 请求拦截
                .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests.anyRequest().access(myAuthorizationManager))
                // 退出
                .logout(logout->logout.logoutUrl("/logout")
                        .deleteCookies("JSESSIONID")
                        .invalidateHttpSession(true)
                        .logoutSuccessHandler(new MyLogoutSuccessHandler()));
        // Jwt拦截器
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        // 账号登录拦截器
        httpSecurity.addFilterAt(usernameLoginFilter(httpSecurity.getSharedObject(AuthenticationManager.class)), UsernamePasswordAuthenticationFilter.class)
                .userDetailsService(myUsernamePasswordDetailsService);

        // 手机号码登录拦截器
        httpSecurity.addFilterAt(phoneLoginFilter(httpSecurity.getSharedObject(AuthenticationManager.class)), UsernamePasswordAuthenticationFilter.class)
                .userDetailsService(myPhoneDetailsService);
        return httpSecurity.build();
    }

}
